﻿
using Modbus.Device;
using System;
using System.Data;
using System.Net.Sockets;
using System.Text;
using System.Timers;
using System.Windows.Forms;
using Microsoft.Extensions.Configuration;
using System.Configuration;
using static System.Windows.Forms.Design.AxImporter;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections.Generic;



// Application code should start here.

namespace Modbus_Master
{
    public partial class Form1 : Form
    {
        [DllImport("kernel32")]
        private static extern long GetPrivateProfileString(string section, string key, string def, StringBuilder retval, int size, string filepath);
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filepath);

        System.Timers.Timer t = new System.Timers.Timer(1000);
        bool[] posedge = new bool[100];
        bool[] negedge = new bool[100];
        string[] alarm_inf = { 
                            "相序错误",
                            "A相系统过流",
                            "B相系统过流",
                            "C相系统过流",
                            "A相逆变器输出过流",
                            "B相逆变器输出过流",
                            "C相逆变器输出过流",
                            "直流母线过压报警",
                            "整流A相电流过流",
                            "整流B相电流过流",
                            "直流母线欠压报警",
                            "整流C相电流过流",
                            "A相逆变器峰值过流故障",
                            "B相逆变器峰值过流故障",
                            "C相逆变器峰值过流故障",
                            "A相整流器峰值过流故障",
                            "B相整流器峰值过流故障",
                            "C相整流器峰值过流故障",
                            "整流A相交流熔丝断开",
                            "整流B相交流熔丝断开",
                            "整流C相交流熔丝断开",
                            "逆变A相交流熔丝断开",
                            "逆变B相交流熔丝断开",
                            "逆变C相交流熔丝断开",
                            "进线开关异常",
                            "旁路开关异常",
                            "出线开关异常",
                            "A相滤波电容过流",
                            "B相滤波电容过流",
                            "C相滤波电容过流",
                            "整流预充电接触器异常",
                            "整流主回路接触器异常",
                            "逆变侧接触器异常",
                            "A相逆变器软件过压故障",
                            "B相逆变器软件过压故障",
                            "C相逆变器软件过压故障",
                            "A相逆变器硬件过压故障",
                            "B相逆变器硬件过压故障",
                            "C相逆变器硬件过压故障",
                            "锁相故障",
                            "AVC输出欠压报警",
                            "交流软启超时",
                            "AVC输出超时",
                            "参数保存故障",
                            "逆变A相IGBT故障",
                            "逆变B相IGBT故障",
                            "逆变C相IGBT故障",
                            "整流A相IGBT故障",
                            "整流B相IGBT故障",
                            "整流C相IGBT故障",
                            "A相IGBT过温报警",
                            "B相IGBT过温报警",
                            "C相IGBT过温报警",
                            "SCR过温报警",
                            "A相SCR短路故障",
                            "B相SCR短路故障",
                            "C相SCR短路故障",
                            "A相SCR开路故障",
                            "B相SCR开路故障",
                            "C相SCR开路故障",
                            "环境温度报警",
                            "电抗器过温报警",
                            "急停",
                            "SCR风机故障",
                            "电网电压小于百分之40报警",
                            "电网电压小于百分之85补偿超时报警",
                            "电网电压小于百分之50补偿超时报警",
                            "滤波电容接触器故障",
                            "模块风机接触器故障",
                            "SCR风机接触器故障",
                            "柜门风机接触器故障"
                            };
        ModbusIpMaster master;
        ushort startAddress = 0;
        ushort numInputs = 10;
        byte slaveID = 1;
        string path = Application.StartupPath + "/AVCconfig.ini";
        bool RUN_LED = false;
        ulong table_num = 0;
        DataTable dt = new DataTable();
        public Form1()
        {
            InitializeComponent();          
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            t.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);//到达时间的时候执行事件；
            t.AutoReset = true;//设置是执行一次（false）还是一直执行(true)；
            t.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件；
            t.SynchronizingObject = this;//初始化定时器，解决跨线程操作错误
            t.Stop(); //先关闭定时器
            //读取配置文件 如果没有则 192.168.1.2 为默认值

            txt_ip.Text =  ReadIni("IP_SET", "IP", "127.0.0.1", 255, path);
            txt_port.Text=  ReadIni("PORT_SET", "port", "502", 255, path);

            textBox_SlaveID.Text = ReadIni("SLAVEID_SET", "slaveID", "1", 255, path);
            slaveID = byte.Parse(textBox_SlaveID.Text);
            //写入config.ini
/*            WriteIni("IP_SET", "IP", this.txt_ip.Text, path);
            WriteIni("PORT_SET", "port", this.txt_port.Text, path);
            WriteIni("SLAVEID_SET", "slaveID", this.textBox_SlaveID.Text, path);*/
            btn_connect.PerformClick();
           // System.Globalization.CultureInfo.CurrentCulture.ClearCachedData();
            List<FileInfo> lst = new List<FileInfo>();
            List<FileInfo> lstFiles = getFile(Application.StartupPath, ".csv", lst);//遍历当前文件夹csv文件
            string find_csv_name = null;
            if (lstFiles.Count != 0)
            {
                //dt = ReadCSV(Application.StartupPath + "/2022.csv", out table_num);
                //dt = ReadCSV(lstFiles[0], out table_num);
                foreach (FileInfo shpFile in lstFiles)
                {
                    find_csv_name = shpFile.FullName ;
                }
                //dt = ReadCSV(find_csv_name, out table_num);
                dt = ReadCSV(Application.StartupPath + "/AVClog.csv", out table_num);


            }
            else
            {
                dt.Columns.Add("序号", typeof(string));
                dt.Columns.Add("日期", typeof(string));
                dt.Columns.Add("时间", typeof(string));
                dt.Columns.Add("事件类型", typeof(string));
                dt.Columns.Add("事件详情", typeof(string));
            }
                dataGridView1.DataSource = dt;
            dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;//标题居中
            //dataGridView1.ColumnHeadersVisible = false;//列头隐藏
            dataGridView1.RowHeadersVisible = false;//行头隐藏

            //dataGridView1.Rows.Add(new object[] { "111","222" });


        }


        /// <summary>
        /// 读配置文件
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="def"></param>
        /// <param name="size"></param>
        /// <param name="filepath"></param>
        /// <returns></returns>
        private  String ReadIni(string section, string key, string def, int size, string filepath)
        {
            StringBuilder sb = new StringBuilder();
            GetPrivateProfileString(section, key, def, sb, size, filepath);
            return sb.ToString();
        }
        /// <summary>
        /// 写入数据到配置文件
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="val"></param>
        /// <param name="filepath"></param>
        /// <returns></returns>
        private  long WriteIni(string section, string key, string val, string filepath)
        {
            return WritePrivateProfileString(section, key, val, filepath);
        }
        /// <summary>
        /// 获得目录下所有文件或指定文件类型文件(包含所有子文件夹)
        /// </summary>
        /// <param name="path">文件夹路径</param>
        /// <param name="extName">扩展名可以多个 例如 .mp3.wma.rm</param>
        /// <returns>List<FileInfo></returns>
        private static List<FileInfo> getFile(string path, string extName, List<FileInfo> lst)
        {
            try
            {

                string[] dir = Directory.GetDirectories(path); //文件夹列表   
                DirectoryInfo fdir = new DirectoryInfo(path);
                FileInfo[] file = fdir.GetFiles();
                //FileInfo[] file = Directory.GetFiles(path); //文件列表   
                if (file.Length != 0 || dir.Length != 0) //当前目录文件或文件夹不为空                   
                {
                    foreach (FileInfo f in file) //显示当前目录所有文件   
                    {
                        if (extName.ToLower().IndexOf(f.Extension.ToLower()) >= 0)
                        {
                            lst.Add(f);
                        }
                    }
                    foreach (string d in dir)
                    {
                        getFile(d, extName, lst);//递归   
                    }
                }
                return lst;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void btn_connect_Click(object sender, EventArgs e)
        {
            Error(false);
            try
            {
                TcpClient client = new TcpClient(txt_ip.Text.Trim().ToString(), int.Parse(txt_port.Text.Trim().ToString()));
                client.SendTimeout = 1;
                master = ModbusIpMaster.CreateIp(client);
                if (master != null)
                {
                    toolStripLabel_meg.Text = $"{txt_ip.Text}:{txt_port.Text}连接成功！";
                    toolStripLabel2.Image = global::Modbus_Master.Properties.Resources.连接成功;
                    WriteIni("IP_SET", "IP", this.txt_ip.Text, path);
                    WriteIni("PORT_SET", "port", this.txt_port.Text, path);
                    WriteIni("SLAVEID_SET", "slaveID", this.textBox_SlaveID.Text, path);
                    t.Start();//开启定时器
                }

                btn_disconnect.Enabled = true;
                btn_connect.Enabled = false;
            }
            catch (Exception eee)
            {
                Error(true, eee);
            }
        }


        private void btn_disconnect_Click(object sender, EventArgs e)
        {
            t.Stop(); //先关闭定时器
            master.Dispose();

            if (master.Transport == null)
            {
                toolStripLabel_meg.Text = $"{txt_ip.Text}：{txt_port.Text}连接已断开！";
                toolStripLabel2.Image = global::Modbus_Master.Properties.Resources.连接断开;
            }
            btn_disconnect.Enabled = false ;
            btn_connect.Enabled = true;
        }

        private void btn_Read_Click(object sender, EventArgs e)
        {
            WriteIni("IP_SET", "IP", this.txt_ip.Text, path);
            WriteIni("PORT_SET", "port",this.txt_port.Text, path);
            WriteIni("SLAVEID_SET", "slaveID" ,this.textBox_SlaveID.Text, path);
        }
        private Int16 ushort2int16(ushort udata)
        {
            //0~65535
            // -32768~32767
            Int16 temp;
            if (udata < 32768)
                temp = Convert.ToInt16(udata);
            else
            {
                temp = Convert.ToInt16(65535 - udata);
                temp = (short)-(temp+1);
            }
                
            return temp;
        }
        private void OnTimedEvent(object sender, ElapsedEventArgs e)
        {
            //bool connect = master.Transport == null;
            bool REG_connect = false;
            bool DIG_connect = false;
            
            RUN_LED = !RUN_LED;
            t.Stop(); //先关闭定时器
            /*            DataTable dt = new DataTable();
                        dt.Columns.Add("地址", typeof(int));
                        dt.Columns.Add("值", typeof(ushort));*/
            //bool [] coils = Coil_Read();


            ushort[] datas = ModbusRead();
            if (datas != null)
            {
                REG_connect = true;
/*                for (int i = 0; i < datas.Length; i++)
                {

                    dt.Rows.Add(new object[] { i + startAddress, datas[i] });

                }*/
                //电网
                this.textBox1.Text = datas[0].ToString() + "V";//电网AB 电压
                this.textBox2.Text = datas[1].ToString() + "V";//电网BC 电压
                this.textBox3.Text = datas[2].ToString() + "V";//电网CA 电压
                this.textBox4.Text = datas[21].ToString() + "Hz";//电网频率
                //负载
                this.textBox5.Text = datas[12].ToString() + "V";//负载电压 A
                this.textBox6.Text = datas[13].ToString() + "V";//负载电压 B
                this.textBox7.Text = datas[14].ToString() + "V";//负载电压 C
                this.textBox8.Text = datas[3].ToString() + "A";//负载电流 A
                this.textBox9.Text = datas[4].ToString() + "A";//负载电流 B
                this.textBox10.Text = datas[5].ToString() + "A";//负载电流 C
                //整流器
                this.textBox14.Text = datas[9].ToString() + "A";//整流器 电流 A
                this.textBox15.Text = datas[10].ToString() + "A";//整流器 电流 B
                this.textBox16.Text = datas[11].ToString() + "A";//整流器 电流 C
                
                
                this.textBox17.Text = ushort2int16(datas[22]).ToString() + "℃";//整流器 温度 SRC
                this.textBox18.Text = ushort2int16(datas[19]).ToString() + "℃";//整流器 温度 模块
                this.textBox19.Text = ushort2int16(datas[23]).ToString() + "℃";//整流器 温度 环境
                this.textBox12.Text = datas[17].ToString() + "A";//整流器 滤波电流
                //this.textBox20.Text = "待机/运行";
                //逆变器
                this.textBox21.Text = datas[6].ToString() + "A";//逆变器 电流 A
                this.textBox22.Text = datas[7].ToString() + "A";//逆变器 电流 B
                this.textBox23.Text = datas[8].ToString() + "A";//逆变器 电流 C
                this.textBox24.Text = ushort2int16(datas[20]).ToString() + "℃";//逆变器 模块温度
                this.textBox25.Text = ushort2int16(datas[15]).ToString() + "V";//逆变器 母线电压
                //this.textBox26.Text = "待机/运行";//逆变器 母线电压
                this.textBox11.Text = datas[16].ToString()+"A";//滤波电流  取A相 
                this.textBox27.Text = datas[24].ToString();//扰动次数


                //t.Start(); //执行完毕后再开启器
            }
            else
            {
                REG_connect = false;
            }
            bool[] Digital = Coil_Read();
            if (Digital != null)
            {
                DIG_connect = true;
                if (Digital[0] == true)//设备
                    this.textBox13.Text = "运行";
                else
                    this.textBox13.Text = "停机";
                if (Digital[3] == true)//整流器
                    this.textBox20.Text = "运行";
                else
                    this.textBox20.Text = "待机";
                if (Digital[4] == true)//逆变器
                    this.textBox26.Text = "运行";
                else
                    this.textBox26.Text = "待机";
                if (Digital[1] == true)
                    this.label56.ForeColor = System.Drawing.Color.IndianRed;//故障状态 40001.1 
                else
                    this.label56.ForeColor = System.Drawing.Color.DimGray;//故障状态 40001.1
                if (Digital[15] == true)
                    this.label57.ForeColor = System.Drawing.Color.IndianRed;//主接触器 40001.15
                else
                    this.label57.ForeColor = System.Drawing.Color.DimGray;//主接触器 40001.15
                if (Digital[5] == true)
                    this.label58.ForeColor = System.Drawing.Color.IndianRed;//预充电接触器 40001.5
                else
                    this.label58.ForeColor = System.Drawing.Color.DimGray;//预充电接触器 40001.5
                if (Digital[8] == true)
                    this.label59.ForeColor = System.Drawing.Color.IndianRed;//逆变器接触器 40001.8
                else
                    this.label59.ForeColor = System.Drawing.Color.DimGray;//逆变器接触器 40001.8
                if(Digital[2] == true)
                    this.label60.ForeColor = System.Drawing.Color.IndianRed;//补偿状态
                else
                    this.label60.ForeColor = System.Drawing.Color.DimGray;//补偿状态
                //this.label61.ForeColor = System.Drawing.Color.IndianRed;//SCR风机
                if (Digital[16] == true)
                    this.label62.ForeColor = System.Drawing.Color.IndianRed;//相序错误 40003.0
                else
                    this.label62.ForeColor = System.Drawing.Color.DimGray;//相序错误 40003.0
                if (Digital[9] == true)
                    this.label63.ForeColor = System.Drawing.Color.IndianRed;//SCR状态
                else
                    this.label63.ForeColor = System.Drawing.Color.DimGray;//A相SCR状态

                if (Digital[12] == true)
                    this.label64.ForeColor = System.Drawing.Color.IndianRed;//进线断路器 40001.12
                else
                    this.label64.ForeColor = System.Drawing.Color.DimGray;//进线断路器 40001.12
                if (Digital[13] == true)
                    this.label65.ForeColor = System.Drawing.Color.IndianRed;//出线断路器 40001.13
                else
                    this.label65.ForeColor = System.Drawing.Color.DimGray;//出线断路器 40001.13
                if (Digital[14] == true)
                    this.label66.ForeColor = System.Drawing.Color.IndianRed;//旁路断路器 40001.14
                else
                    this.label66.ForeColor = System.Drawing.Color.DimGray;//旁路断路器 40001.14
                if (Digital[6] == true)
                    this.label67.ForeColor = System.Drawing.Color.IndianRed;//旋钮开关   40001.6
                else
                    this.label67.ForeColor = System.Drawing.Color.DimGray;//旋钮开关   40001.6
                if (Digital[7] == true)
                    this.label68.ForeColor = System.Drawing.Color.IndianRed;//急停按钮   40001.7
                else
                    this.label68.ForeColor = System.Drawing.Color.DimGray;//急停按钮   40001.7
                if (Digital[87] == true)
                    this.label4.ForeColor = System.Drawing.Color.IndianRed;//SCR风机状态  10088
                else
                    this.label4.ForeColor = System.Drawing.Color.DimGray;//SCR风机状态  10088
                if (Digital[88] == true)
                    this.label61.ForeColor = System.Drawing.Color.IndianRed;//滤波接触器状态   10089
                else
                    this.label61.ForeColor = System.Drawing.Color.DimGray;//滤波接触器状态   10089
                if (Digital[89] == true)
                    this.label43.ForeColor = System.Drawing.Color.IndianRed;//模块风机状态  10090
                else
                    this.label43.ForeColor = System.Drawing.Color.DimGray;//模块风机状态  10090
                if (Digital[90] == true)
                    this.label48.ForeColor = System.Drawing.Color.IndianRed;//柜门风机状态   10091
                else
                    this.label48.ForeColor = System.Drawing.Color.DimGray;//柜门风机状态   10091
            }
            else {
                REG_connect = false;
            }
           // dataGridView1.DataSource = dt;

/*            dataGridView1.Columns[0].ReadOnly = true;
            dataGridView1.Columns[1].ReadOnly = false;*/
            if ((REG_connect == true) || (DIG_connect == true))
            {
                t.Start();
            }
            else {
                //btn_disconnect.PerformClick();
                master.Dispose();

                if (master.Transport == null)
                {
                    toolStripLabel_meg.Text = $"{txt_ip.Text}：{txt_port.Text}连接已断开！";
                    toolStripLabel2.Image = global::Modbus_Master.Properties.Resources.连接断开;
                }
                btn_disconnect.Enabled = false;
                btn_connect.Enabled = true;
            }
            
        }

        public bool get_posedge(bool Value ,int num)
        {

            if (Value && !posedge[num])
            {
                posedge[num] = true;
                return true;
            }
            if (!Value)
                posedge[num] = false;
            return false;

        }
        public bool get_negedge(bool Value, ushort num)
        {

            if (!Value && negedge[num])
            {
                negedge[num] = false;
                return true;
            }


            if (Value)
                negedge[num] = true;
            return false;
        }
        private void btn_Write_Click(object sender, EventArgs e)
        {

        }
        /// <summary>  
        /// 取整数的某一位  
        /// </summary>  
        /// <param name="_Resource">要取某一位的整数</param>  
        /// <param name="_Mask">要取的位置索引，自右至左为 索引0开始</param>  
        /// <returns>返回某一位的值（0或者1）</returns>  
        private bool GetBit(int _Resource, int _Mask)
        {
            int temp;
            bool res = false;
            temp = _Resource >> _Mask;
            temp &= 0x00000001;
            if(temp>0)
                res = true;
            else
                res = false;
            return res;
                
        }

        private ushort[] ModbusRead()
        {
            Error(false);
            try
            {
                slaveID = byte.Parse(textBox_SlaveID.Text);
                ushort[] datas = new ushort[25];

                //ushort[] holdingRegisters = master.ReadHoldingRegisters(slaveID, startAddress, numInputs);
                ushort[] holdingRegisters = master.ReadInputRegisters(slaveID, 0, 25);
                datas = holdingRegisters;
                return datas;
            }
            catch (Exception eee)
            {
                Error(true, eee);
                return null;
            }
        }



        private bool[] Coil_Read()
        {
            Error(false);
            try
            {
                startAddress = 0;
                numInputs = 91;
                slaveID = byte.Parse(textBox_SlaveID.Text);
                bool[] datas = new bool[91];
                bool[] coils = master.ReadInputs(slaveID, startAddress, numInputs);
                datas = coils;
                DateTime dateTime = DateTime.Now;
                string date = dateTime.ToString("yyyy-MM-dd");
                string time = dateTime.ToString("HH:mm:ss");
                
                for (int i = 0; i < 71; i++)
                {

                    if (get_posedge(datas[1], 1))
                    {
                        table_num += 1;
                        dt.Rows.Add(new object[] {   table_num.ToString(),
                            date,
                            time,
                            "报警",
                            "设备故障"
                        });
                        string[] csv_str = new string[5];
                        csv_str[0] = table_num.ToString();
                        csv_str[1] = date;
                        csv_str[2] = time;
                        csv_str[3] = "报警";
                        csv_str[4] = "设备故障";
                        WriteLineCSV(Application.StartupPath + "/AVClog.csv", csv_str);
                        //dataGridView1.DataSource = dt;
                    }
                    /*if (get_posedge(datas[0], 0))
                    {
                        table_num += 1;
                        dt.Rows.Add(new object[] {   table_num.ToString(),
                            date,
                            time,
                            "事件",
                            "设备启动"
                        });
                        string[] csv_str = new string[5];
                        csv_str[0] = table_num.ToString();
                        csv_str[1] = date;
                        csv_str[2] = time;
                        csv_str[3] = "事件";
                        csv_str[4] = "设备启动";
                        WriteLineCSV(Application.StartupPath + "/2022.csv", csv_str);
                        //dataGridView1.DataSource = dt;
                    }

                    if (get_negedge(datas[0], 0))
                    {
                        table_num += 1;
                        dt.Rows.Add(new object[] {   table_num.ToString(),
                            date,
                            time,
                            "事件",
                            "设备停机"
                        });
                        string[] csv_str = new string[5];
                        csv_str[0] = table_num.ToString();
                        csv_str[1] = date;
                        csv_str[2] = time;
                        csv_str[3] = "事件";
                        csv_str[4] = "设备停机";
                        WriteLineCSV(Application.StartupPath + "/2022.csv", csv_str);
                        //dataGridView1.DataSource = dt;
                    }*/
                    if (get_posedge(datas[i + 16], i + 16))
                    {
                        table_num += 1;
                        dt.Rows.Add(new object[] {   table_num.ToString(),
                            date,
                            time,
                            "报警",
                            alarm_inf[i]
                            });
                        string[] csv_str = new string[5];
                        csv_str[0] = table_num.ToString();
                        csv_str[1] = date;
                        csv_str[2] = time;
                        csv_str[3] = "报警";
                        csv_str[4] = alarm_inf[i];
                        WriteLineCSV(Application.StartupPath + "/AVClog.csv", csv_str);
                        // dataGridView1.DataSource = dt;
                    }
                    dataGridView1.DataSource = dt;


                    //WriteCSV(Application.StartupPath + "/2022.csv", dt);


                }
                
                return datas;
            }
            catch (Exception eee)
            {
                Error(true, eee);
                return null;
            }
        }


        /// <summary>
        /// CSV 写一行四列
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="str">要写入的四列数据</param>
        private void WriteLineCSV(string fileName, string[] str)
        {
            FileStream fs;
            StreamWriter sw;
            string data = null;

            //判断文件是否存在,存在就不再次写入列名
            if (!File.Exists(fileName))
            {
                fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
                sw = new StreamWriter(fs, Encoding.UTF8);

                //写出列名称
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    data += dt.Columns[i].ColumnName.ToString();
                    if (i < dt.Columns.Count - 1)
                    {
                        data += ",";//中间用，隔开
                    }
                }
                sw.WriteLine(data);
            }
            else
            {
                fs = new FileStream(fileName, FileMode.Append, FileAccess.Write);
                sw = new StreamWriter(fs, Encoding.UTF8);
            }

            //写出各行数据
            //for (int i = 0; i < dt.Rows.Count; i++)
            {
                data = null;
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    data += str[j];
                    if (j < dt.Columns.Count - 1)
                    {
                        data += ",";//中间用，隔开
                    }
                }
                sw.WriteLine(data);
            }
            sw.Close();
            fs.Close();
        }
        /// <summary>
        /// 写入CSV
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="dt">要写入的datatable</param>
        private  void WriteCSV(string fileName, DataTable dt)
        {
            FileStream fs;
            StreamWriter sw;
            string data = null;

            //判断文件是否存在,存在就不再次写入列名
            if (!File.Exists(fileName))
            {
                fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
                sw = new StreamWriter(fs, Encoding.UTF8);

                //写出列名称
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    data += dt.Columns[i].ColumnName.ToString();
                    if (i < dt.Columns.Count - 1)
                    {
                        data += ",";//中间用，隔开
                    }
                }
                sw.WriteLine(data);
            }
            else
            {
                fs = new FileStream(fileName, FileMode.Append, FileAccess.Write);
                sw = new StreamWriter(fs, Encoding.UTF8);
            }

            //写出各行数据
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                data = null;
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    data += dt.Rows[i][j].ToString();
                    if (j < dt.Columns.Count - 1)
                    {
                        data += ",";//中间用，隔开
                    }
                }
                sw.WriteLine(data);
            }
            sw.Close();
            fs.Close();
        }

        /// <summary>
        /// 读取CSV文件
        /// </summary>
        /// <param name="fileName">文件路径</param>
        private  DataTable ReadCSV(string fileName,out ulong rows)
        {
            DataTable dt = new DataTable();
            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            StreamReader sr = new StreamReader(fs, Encoding.UTF8);
            rows = 0;
            //记录每次读取的一行记录
            string strLine = null;
            //记录每行记录中的各字段内容
            string[] arrayLine = null;
            //判断，若是第一次，建立表头
            bool isFirst = true;

            //列的个数
            int dtColumns = 0;

            //逐行读取CSV文件
            while ((strLine = sr.ReadLine()) != null)
            {
                strLine = strLine.Trim();//去除头尾空格
                 
                arrayLine = strLine.Split(',');//分隔字符串，返回数组

                if (isFirst)  //建立表头
                {
                    dtColumns = arrayLine.Length;//列的个数
                    for (int i = 0; i < dtColumns; i++)
                    {
                        dt.Columns.Add(arrayLine[i]);//每一列名称
                    }
                    isFirst = false;
                }
                else   //表内容
                {
                    DataRow dataRow = dt.NewRow();//新建一行
                    for (int j = 0; j < dtColumns; j++)
                    {
                        if (arrayLine.Length > j)
                        {
                            dataRow[j] = arrayLine[j];
                        }
                    }
                    dt.Rows.Add(dataRow);//添加一行
                    rows += 1;
                }
            }
            sr.Close();
            fs.Close();

            return dt;
        }
    
    private void Error(bool IsError, Exception eee = null)
        {
            if (!IsError)
            {
                toolStripLabel_errImage.Image = null;
                toolStripLabel_err.Text = null;
            }
            else
            {
                toolStripLabel_errImage.Image = global::Modbus_Master.Properties.Resources.连接失败;
                toolStripLabel_err.Text = eee.Message;
            }
        }

        private void Error(string eee = null)
        {

            toolStripLabel_errImage.Image = global::Modbus_Master.Properties.Resources.连接失败;
            toolStripLabel_err.Text = eee;

        }

        private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            Error(e.RowIndex + "-" + e.ColumnIndex  );
            //ushort Address = ushort.Parse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex - 1].Value.ToString());
            //ushort Value = ushort.Parse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
            //ModbusWrite(Address, Value);



        }


        private void ModbusWrite(ushort Address, ushort Value)
        {
            Error(false);
            try
            {
               
                slaveID = byte.Parse(textBox_SlaveID.Text);
                ushort[] datas = new ushort[numInputs];
               

/*                switch (comboBox_FunCode.SelectedIndex)
                {
                    case 0:
                         master.WriteSingleCoil(slaveID, Address, Value==0?false:true);
                        break;
                    case 1:
                        master.WriteSingleCoil(slaveID, Address, Value == 0 ? false : true);
                        break;
                    case 2:
                        master.WriteSingleRegister(slaveID, Address, Value);
                        break;
                    case 3:
                        master.WriteSingleRegister(slaveID, Address, Value);
                        break;
                    default:
                        MessageBox.Show("功能码错误");
                        datas = null;
                        break;
                }*/
              
            }
            catch (Exception eee)
            {
                Error(true, eee);
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void dataGridView1_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
        {

        }
    }
}
